<template>
  <div class="flex h-full row">
    <div class="w-1/4 p-2">
      <h3>组件选取列表</h3>
      <draggable
        v-model="formTypeList"
        class="flex flex-wrap p-4 gap-2 justify-center"
        :clone="pushFormTypeItemToFormList"
        :group="{ name: 'people', pull: 'clone', put: false, sort: false, disabled: true }"
        item-key="id"
      >
        <template #item="{ element }">
          <div
            class="py-2 w-[calc(50%-10px)] text-center border text-sm border-gray-300 border-dashed rounded cursor-pointer hover:bg-gray-100"
          >
            {{ formTypeMap[element.type] }}
          </div>
        </template>
      </draggable>
    </div>
    <div class="w-1/2 p-1 border border-gray-300 border-solid rounded">
      <div class="flex justify-between p-2">
        <h3>表单展示列表</h3>
        <div class="flex gap-1">
          <el-link type="primary" :underline="false" @click="handlePreviewFormConfig">
            表单配置
          </el-link>
          <el-link type="primary" :underline="false" @click="handleImportFormConfig">导入</el-link>
          <el-link
            v-if="formList.length > 0"
            type="primary"
            :underline="false"
            @click="handleExportFormConfig"
          >
            导出
          </el-link>
          <el-link
            v-if="formList.length > 0"
            type="primary"
            :underline="false"
            @click="handlePreviewFormConfig"
          >
            预览
          </el-link>
          <el-link
            v-if="formList.length > 0"
            type="danger"
            :underline="false"
            @click="handleClearFormConfig"
          >
            清空
          </el-link>
        </div>
      </div>
      <div class="basic-form submit">
        <el-form :model="form" label-width="120px">
          <el-row class="p-2 border border-gray-300 border-dashed">
            <draggable
              v-model="formList"
              class="flex flex-wrap w-full p-2"
              group="people"
              item-key="id"
            >
              <template #item="{ element: formItem, index }">
                <el-col
                  :span="formItem.col || 24"
                  class="relative p-3 mb-2 border border-dashed cursor-pointer group/col"
                  :class="selectIndex === index ? 'border-blue-500' : 'border-gray-300'"
                  @click="changeSelectIndexToConfig(formItem, index)"
                >
                  <h3 v-if="formItem.type === 'title'" :class="formItem.className">
                    {{ formItem.label }}
                  </h3>
                  <el-form-item
                    v-else
                    :label="formItem.label"
                    :label-width="formItem.labelWidth ?? ''"
                    :prop="formItem.field"
                    :rules="getFormItemRules(formItem.rules)"
                  >
                    <!-- :rules="formItem.rules ? JSON.parse(formItem.rules) : null" -->
                    <el-input
                      v-if="textTypeList.includes(formItem.type)"
                      v-model.trim="form[formItem.field]"
                      :type="formItem.type"
                      :clearable="formItem.clearable ?? true"
                      :class="formItem.className"
                      :minlength="formItem.minlength ?? 0"
                      :maxlength="formItem.maxlength ?? 142"
                      :show-word-limit="formItem.showWordLimit ?? false"
                      :rows="formItem.rows ?? 2"
                      :show-password="
                        (formItem.showPassword ?? true) && formItem.type === 'password'
                      "
                      :disabled="formItem.disabled"
                      :readonly="formItem.readonly"
                      :placeholder="getPlaceholder(formItem.type, formItem.placeholder)"
                    />
                    <el-radio-group
                      v-else-if="formItem.type === 'radio'"
                      v-model="form[formItem.field]"
                    >
                      <div v-if="formItem.checkedType === 'default'">
                        <el-radio
                          v-for="item in formItem.options"
                          :key="item.value"
                          :label="item.value"
                          :border="formItem.checkedBorder ?? false"
                          :disabled="formItem.disabled ?? false"
                        >
                          {{ item.label }}
                        </el-radio>
                      </div>
                      <div v-else-if="formItem.checkedType === 'button'">
                        <el-radio-button
                          v-for="item in formItem.options"
                          :key="item.value"
                          :label="item.value"
                          :border="formItem.checkedBorder ?? false"
                          :disabled="formItem.disabled ?? false"
                        >
                          {{ item.label }}
                        </el-radio-button>
                      </div>
                    </el-radio-group>
                    <el-checkbox-group
                      v-else-if="formItem.type === 'checkbox'"
                      v-model="form[formItem.field]"
                      :disabled="formItem.disabled ?? false"
                    >
                      <div v-if="formItem.checkedType === 'default'">
                        <el-checkbox
                          v-for="item in formItem.options"
                          :key="item.value"
                          :label="item.value"
                          :border="formItem.checkedBorder ?? false"
                        >
                          {{ item.label }}
                        </el-checkbox>
                      </div>
                      <div v-else-if="formItem.checkedType === 'button'">
                        <el-checkbox-button
                          v-for="item in formItem.options"
                          :key="item.value"
                          :label="item.value"
                        >
                          {{ item.label }}
                        </el-checkbox-button>
                      </div>
                    </el-checkbox-group>
                    <el-color-picker
                      v-else-if="formItem.type === 'color' && formItem.show"
                      v-model="form[formItem.field]"
                      :popper-class="formItem.popperClass"
                      :class="formItem.className"
                      :disabled="formItem.disabled ?? false"
                      :show-alpha="formItem.showAlpha ?? false"
                      :predefine="
                        formItem.predefine ?? ['#ff4500', '#ffd700', '#1e90ff', '#c71585']
                      "
                    />
                    <el-input-number
                      v-else-if="formItem.type === 'number'"
                      v-model.trim="form[formItem.field]"
                      :class="formItem.className"
                      :min="formItem.min || -Infinity"
                      :max="formItem.max || Infinity"
                      :step="formItem.step || 1"
                      :step-strictly="formItem.stepStrictly ?? false"
                      :precision="formItem.precision ?? 0"
                      :disabled="formItem.disabled ?? false"
                      :readonly="formItem.readonly ?? false"
                      :controls="formItem.controls ?? true"
                      :controls-position="formItem.controlsPosition ?? ''"
                      :placeholder="getPlaceholder(formItem.type, formItem.placeholder)"
                    />
                    <el-select
                      v-else-if="formItem.type === 'select'"
                      v-model="form[formItem.field]"
                      :class="formItem.className"
                      :popper-class="formItem.popperClass"
                      :clearable="formItem.clearable ?? true"
                      filterable
                      :teleported="formItem.teleported ?? true"
                      :disabled="formItem.disabled"
                      :multiple="formItem.multiple"
                      :multiple-limit="formItem.multipleLimit ?? 0"
                      :collapse-tags="formItem.collapseTags ?? true"
                      :collapse-tags-tooltip="formItem.collapseTagsTooltip ?? true"
                      :placeholder="getPlaceholder(formItem.type, formItem.placeholder)"
                    >
                      <el-option
                        v-for="selectItem in formItem.options ?? []"
                        :key="
                          selectItem[
                            formItem.optionsFrom === 'dict'
                              ? 'dictValue'
                              : formItem.props?.value || 'value'
                          ]
                        "
                        :label="
                          selectItem[
                            formItem.optionsFrom === 'dict'
                              ? 'dictLabel'
                              : formItem.props?.label || 'label'
                          ]
                        "
                        :value="
                          selectItem[
                            formItem.optionsFrom === 'dict'
                              ? 'dictValue'
                              : formItem.props?.value || 'value'
                          ]
                        "
                      />
                    </el-select>
                    <el-cascader
                      v-else-if="formItem.type === 'cascader'"
                      v-model="form[formItem.field]"
                      :class="formItem.className"
                      :popper-class="formItem.popperClass"
                      :options="formItem.options ?? []"
                      :props="formItem.props ?? {}"
                      :clearable="formItem.clearable ?? true"
                      :filterable="formItem.filterable ?? true"
                      :disabled="formItem.disabled ?? false"
                      :show-all-levels="formItem.showAllLevels ?? true"
                      :teleported="formItem.teleported ?? true"
                      :collapse-tags="formItem.collapseTags ?? true"
                      :collapse-tags-tooltip="formItem.collapseTagsTooltip ?? true"
                      :separator="formItem.separator ?? '/'"
                      :placeholder="getPlaceholder(formItem.type, formItem.placeholder)"
                    />
                    <el-tree-select
                      v-else-if="formItem.type === 'treeSelect'"
                      v-model="form[formItem.field]"
                      :class="formItem.className"
                      :popper-class="formItem.popperClass"
                      :data="formItem.options ?? []"
                      :props="formItem.props ?? {}"
                      :check-strictly="formItem?.checkStrictly ?? false"
                      :clearable="formItem.clearable ?? true"
                      :filterable="formItem.filterable ?? true"
                      :readonly="formItem.readonly ?? false"
                      :default-expand-all="formItem.defaultExpandAll ?? false"
                      :teleported="formItem.teleported ?? true"
                      :disabled="formItem.disabled ?? false"
                      :multiple="formItem.multiple ?? false"
                      :multiple-limit="formItem.multipleLimit || 0"
                      :collapse-tags="formItem.collapseTags ?? true"
                      :collapse-tags-tooltip="formItem.collapseTagsTooltip ?? true"
                      :placeholder="getPlaceholder(formItem.type, formItem.placeholder)"
                    />
                    <el-date-picker
                      v-else-if="singleDateTypeList.includes(formItem.type)"
                      v-model="form[formItem.field]"
                      :class="formItem.className"
                      :popper-class="formItem.popperClass"
                      :type="formItem.type"
                      :clearable="formItem.clearable ?? true"
                      :format="getFormatVal(formItem, 'format', 'datetime')"
                      :value-format="getFormatVal(formItem, 'valueFormat', 'datetime')"
                      :disabled="formItem.disabled"
                      :readonly="formItem.readonly"
                      :disabled-date="(time:Date) => getDisabledDate(time, formItem)"
                      :teleported="formItem.teleported ?? true"
                      :placeholder="getPlaceholder(formItem.type, formItem.placeholder)"
                    />
                    <el-date-picker
                      v-else-if="rangeDateTypeList.includes(formItem.type) && formItem.show"
                      v-model="form[formItem.field]"
                      :class="formItem.className"
                      :popper-class="formItem.popperClass"
                      :type="formItem.type"
                      :clearable="formItem.clearable ?? true"
                      :format="getFormatVal(formItem, 'format', 'datetimerange')"
                      :value-format="getFormatVal(formItem, 'valueFormat', 'datetimerange')"
                      :disabled="formItem.disabled"
                      :readonly="formItem.readonly"
                      :disabled-date="(time:Date) => getDisabledDate(time, formItem)"
                      :teleported="formItem.teleported ?? true"
                      :default-time="defaultTime"
                      :range-separator="formItem.rangeSeparator ?? '-'"
                      :unlink-panels="formItem.unlinkPanels ?? true"
                      :start-placeholder="
                        getPlaceholder(formItem.type, formItem.startPlaceholder ?? '开始时间')
                      "
                      :end-placeholder="
                        getPlaceholder(formItem.type, formItem.endPlaceholder ?? '结束时间')
                      "
                    />
                    <Upload
                      v-else-if="formItem.type === 'upload'"
                      v-model="form[formItem.field]"
                      :upload-text="formItem.uploadText ?? '选择文件'"
                      :hide-file="formItem.hideFile ?? false"
                      :drag="formItem.drag ?? false"
                      :list-type="formItem.listType ?? 'picture-card'"
                      :headers="formItem.headers ?? {}"
                      :data="formItem.data ?? {}"
                      :accept="formItem.accept ?? 'image/*'"
                      :limit="formItem.limit ?? 1"
                      :max-size="formItem.maxSize ?? 2"
                    />
                  </el-form-item>
                  <div class="absolute bottom-0 right-0 hidden gap-1 bg-white group-hover/col:flex">
                    <el-icon @click.stop="copyFormListItem(formItem)"><CopyDocument /></el-icon>
                    <el-icon @click.stop="deleteFormListItem(index)"><Delete /></el-icon>
                  </div>
                </el-col>
              </template>
            </draggable>
          </el-row>
        </el-form>
      </div>
    </div>
    <div class="w-1/4 p-2">
      <el-scrollbar class="h-full w-full">
        <component
          :is="selectComponent"
          v-if="typeof selectIndex === 'number'"
          :form-item="formList[selectIndex]"
        />
      </el-scrollbar>
    </div>
  </div>
  <PreviewConfigDialog ref="previewConfigRef" :form-list="formList" />
  <input type="file" class="hidden file-input" accept=".json" @change="handleFileImport" />
</template>

<script lang="ts" setup name="LowCodeConfig">
import { ref, shallowRef } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { CopyDocument, Delete } from '@element-plus/icons-vue'
import { getRandomStr, exportJsToJsonFile } from '@/utils'
import { parseRules } from '@/utils/rules'
import { defaultList } from './defaultList'
import { Upload } from '@/components/Upload'
import { cloneDeep } from 'lodash'
import draggable from 'vuedraggable'
import PreviewConfigDialog from '@/views/form-config/components/PreviewConfigDialog.vue'

const formTypeMap = {
  title: '标题',
  text: '文本输入框',
  radio: '单选框',
  checkbox: '多选框',
  color: '颜色选择器',
  password: '密码输入框',
  textarea: '文本域输入框',
  number: '数字输入框',
  select: '下拉选择器',
  cascader: '级联选择器',
  treeSelect: '树形选择器',
  date: '日期选择器',
  datetimerange: '日期范围选择器',
  upload: '上传组件'
}
const defaultTime: Date[] = [new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 2, 1, 23, 59, 59)]
const module = import.meta.glob('/src/views/form-config/components/**.vue', {
  eager: true,
  import: 'default'
})
// 更换配置组件
const selectIndex = ref<'' | number>('')
const selectComponent = shallowRef()
const textTypeList = ['text', 'password', 'textarea']
const singleDateTypeList = ['date', 'datetime', 'month', 'year'] //, 'dates'
const rangeDateTypeList = ['daterange', 'datetimerange', 'monthrange']
const changeSelectIndexToConfig = async (formItem: SubmitFormSchema, index: number) => {
  selectIndex.value = index
  let componentStr = formItem.type
  if (textTypeList.includes(formItem.type)) {
    componentStr = 'text'
  } else if (singleDateTypeList.includes(formItem.type)) {
    componentStr = 'date'
  } else if (rangeDateTypeList.includes(formItem.type)) {
    componentStr = 'daterange'
  }
  selectComponent.value = module[`/src/views/form-config/components/${componentStr}.vue`]
  console.log(selectComponent.value)
}

const form = ref<Record<string, any>>({})
const formTypeList = ref<SubmitFormSchema[]>(defaultList)
const getFormItemRules = rules => {
  if (typeof rules === 'string') {
    return parseRules(rules)
  }
  return rules
}

// 将formTypeList中的数据push到formList中
const formList = ref<SubmitFormSchema[]>([])
const pushFormTypeItemToFormList = (row: SubmitFormSchema) => {
  selectIndex.value = ''
  return {
    ...cloneDeep(row),
    label: formTypeMap[row.type] || '名称',
    field: getRandomStr(8, false)
  }
}
// 复制
const copyFormListItem = (row: SubmitFormSchema) => {
  const params = cloneDeep(row)
  params.field = params.type === 'title' ? '' : getRandomStr(8, false)
  formList.value.push(params)
  ElMessage.success('复制成功')
}
// 删除
const deleteFormListItem = (index: number) => {
  formList.value.splice(index, 1)
  ElMessage.success('删除成功')
  selectIndex.value = ''
}

// 获取"占位符"
const getPlaceholder = (placeholderType: string, placeholderText: string | undefined) => {
  if (['text', 'textarea', 'number', 'password'].includes(placeholderType)) {
    return placeholderText || '请输入'
  }
  return placeholderText || '请选择'
}
// 返回date-picker组件的format/valueFormat格式
const getFormatVal = (
  formItem: SubmitFormSchema,
  formatField: 'format' | 'valueFormat',
  str: string
): string => {
  return formItem[formatField] ?? 'YYYY-MM-DD' + (formItem.type === str ? ' HH:mm:ss' : '')
}
// 获取"禁用日期"
const getDisabledDate = (time: Date, formItem: SubmitFormSchema): boolean => {
  if (formItem.disabledDateType) {
    const disabledDateTypeMap = {
      before: time.getTime() < Date.now() - 8.64e7,
      after: time.getTime() > Date.now()
    }
    return disabledDateTypeMap[formItem.disabledDateType]
  }
  return false
}
// 预览配置出的表单
const previewConfigRef = ref<InstanceType<typeof PreviewConfigDialog>>()
const handlePreviewFormConfig = () => {
  previewConfigRef.value?.handleOpen('add')
}
// 导入配置json文件
const handleImportFormConfig = () => {
  const inputDom: HTMLInputElement | null = document.querySelector('.file-input')
  inputDom?.click()
}
// 导出配置json文件
const handleExportFormConfig = () => {
  ElMessageBox.prompt('请输入要导出的文件名称：', '提示', {
    confirmButtonText: '确定',
    cancelButtonText: '取消',
    inputPlaceholder: '默认名称：表单配置'
  }).then(({ value }) => {
    exportJsToJsonFile(formList.value, value || '表单配置')
  })
}
const handleClearFormConfig = () => {
  ElMessageBox.confirm('是否清空表单配置?', '提示', {
    confirmButtonText: '确定',
    cancelButtonText: '取消',
    type: 'warning'
  }).then(() => {
    formList.value = []
  })
}
// 将文件导出

// 将json文件导入
const handleFileImport = (event: Event): void => {
  const target = event.target as HTMLInputElement
  const files = target.files?.[0]
  if (!files) {
    return
  }
  const reader = new FileReader()
  reader.onload = (e: any) => {
    try {
      e.target?.result && (formList.value = JSON.parse(e.target.result as string))
    } catch (error) {
      console.error('JSON解析错误', error)
    }
  }
  reader.readAsText(files)
}
</script>
<style scoped lang="scss">
:deep(.basic-form.submit) {
  .el-form-item {
    margin-bottom: 0;
  }
}
</style>
